home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / MNetsrc.hqx / Mac TCP_IP Source v.33 / arp.c next >
Text File  |  1989-03-18  |  12KB  |  434 lines

  1. /* Address Resolution Protocol (ARP) functions. Sits between IP and
  2.  * Level 2, mapping IP to Level 2 addresses for all outgoing datagrams.
  3.  */
  4. #include "global.h"
  5. #include "config.h"
  6. #include "mbuf.h"
  7. #include "timer.h"
  8. #include "iface.h"
  9. #include "enet.h"
  10. #include "ax25.h"
  11. #include "arp.h"
  12. #ifdef PROXY
  13. #include "routing.h"
  14. #endif
  15.  
  16. extern int32 ip_addr;        /* Our IP address */
  17.  
  18. /* ARP entries for particular subnetwork types. The table values
  19.  * are filled in by calls to arp_init() at device attach time
  20.  */
  21. #define    NTYPES    9
  22. struct arp_type arp_type[NTYPES];
  23.  
  24. /* Hash table headers */
  25. struct arp_tab *arp_tab[ARPSIZE];
  26.  
  27. struct arp_stat arp_stat;
  28.  
  29. /* Initialize an entry in the ARP table
  30.  * Called by the device driver at attach time
  31.  */
  32. arp_init(hwtype,hwalen,iptype,arptype,bdcst,format,scan)
  33. unsigned int hwtype;    /* ARP Hardware type */
  34. int hwalen;        /* Hardware address length */
  35. int iptype;        /* Subnet's protocol ID for IP */
  36. int arptype;        /* Subnet's protocol ID for ARP */
  37. char *bdcst;        /* Subnet's broadcast address (if any) */
  38. int (*format)();    /* Function to format hardware addresses */
  39. int (*scan)();        /* Function to scan addresses in ascii */    
  40. {
  41.     register struct arp_type *at;
  42.  
  43.     if(hwtype >= NTYPES)
  44.         return -1;    /* Table too small */
  45.  
  46.     at = &arp_type[hwtype];
  47.     at->hwalen = (int16)hwalen;
  48.     at->iptype = (int16)iptype;
  49.     at->arptype = (int16)arptype;
  50.     at->bdcst = bdcst;
  51.     at->format = format;
  52.     at->scan = scan;
  53.     return 0;
  54. }
  55.  
  56. /* Resolve an IP address to a hardware address; if not found,
  57.  * initiate query and return NULLCHAR.  If an address is returned, the
  58.  * interface driver may send the packet; if NULLCHAR is returned,
  59.  * res_arp() will have saved the packet on its pending queue,
  60.  * so no further action (like freeing the packet) is necessary.
  61.  */
  62. char *
  63. res_arp(interface,hardware,target,bp)
  64. struct interface *interface;    /* Pointer to interface block */
  65. int16 hardware;        /* Hardware type */
  66. int32 target;        /* Target IP address */
  67. struct mbuf *bp;    /* IP datagram to be queued if unresolved */
  68. {
  69.     void arp_output();
  70.     register struct arp_tab *arp;
  71.  
  72.     if((arp = arp_lookup(hardware,target)) != NULLARP && arp->state == ARP_VALID)
  73.         return arp->hw_addr;
  74.     /* Create an entry and put the datagram on the
  75.      * queue pending an answer
  76.      */
  77.     arp = arp_add(target,hardware,NULLCHAR,0,0);
  78.     enqueue(&arp->pending,bp);
  79.     arp_output(interface,hardware,target);
  80.     return NULLCHAR;
  81. }
  82. /* Handle incoming ARP packets. This is almost a direct implementation of
  83.  * the algorithm on page 5 of RFC 826, except for:
  84.  * 1. Outgoing datagrams to unresolved addresses are kept on a queue
  85.  *    pending a reply to our ARP request.
  86.  * 2. The names of the fields in the ARP packet were made more mnemonic.
  87.  * 3. Requests for IP addresses listed in our table as "published" are
  88.  *    responded to, even if the address is not our own.
  89.  */
  90. void
  91. arp_input(interface,bp)
  92. struct interface *interface;
  93. struct mbuf *bp;
  94. {
  95.     struct arp arp;
  96.     struct arp_tab *ap;
  97.     struct arp_type *at;
  98.     struct mbuf *htonarp();
  99. #ifdef PROXY
  100.     struct is_es_tab *prox;
  101.     int32 temp;
  102. #endif    
  103.     arp_stat.recv++;
  104.     if(ntoharp(&arp,&bp) == -1)    /* Convert into host format */
  105.         return;
  106.     if(arp.hardware >= NTYPES){
  107.         /* Unknown hardware type, ignore */
  108.         arp_stat.badtype++;
  109.         return;
  110.     }
  111.     at = &arp_type[arp.hardware];
  112.     if(arp.protocol != at->iptype){
  113.         /* Unsupported protocol type, ignore */
  114.         arp_stat.badtype++;
  115.         return;
  116.     }
  117.     if(uchar(arp.hwalen) > MAXHWALEN || uchar(arp.pralen) != sizeof(int32)){
  118.         /* Incorrect protocol addr length (different hw addr lengths
  119.          * are OK since AX.25 addresses can be of variable length)
  120.          */
  121.         arp_stat.badlen++;
  122.         return;
  123.     }
  124.     if(memcmp(arp.shwaddr,at->bdcst,at->hwalen) == 0){
  125.         /* This guy is trying to say he's got the broadcast address! */
  126.         arp_stat.badaddr++;
  127.         return;
  128.     }
  129.     /* If this guy is already in the table, update its entry
  130.      * unless it's a manual entry (noted by the lack of a timer)
  131.      */
  132.     ap = NULLARP;    /* ap plays the role of merge_flag in the spec */
  133.     if((ap = arp_lookup(arp.hardware,arp.sprotaddr)) != NULLARP
  134.      && ap->timer.start != 0){
  135.         ap = arp_add(arp.sprotaddr,arp.hardware,arp.shwaddr,uchar(arp.hwalen),0);
  136.     }
  137.     /* See if we're the address they're looking for */
  138.     if(arp.tprotaddr == ip_addr){
  139.         if(ap == NULLARP)    /* Only if not already in the table */
  140.             arp_add(arp.sprotaddr,arp.hardware,arp.shwaddr,uchar(arp.hwalen),0);
  141.  
  142.         if(arp.opcode == ARP_REQUEST){
  143.             /* Swap sender's and target's (us) hardware and protocol
  144.              * fields, and send the packet back as a reply
  145.              */
  146.             memcpy(arp.thwaddr,arp.shwaddr,(int16)uchar(arp.hwalen));
  147.             /* Mark the end of the sender's AX.25 address
  148.              * in case he didn't
  149.              */
  150.             if(arp.hardware == ARP_AX25)
  151.                 arp.thwaddr[uchar(arp.hwalen)-1] |= E;
  152.  
  153.             memcpy(arp.shwaddr,interface->hwaddr,at->hwalen);
  154.             arp.tprotaddr = arp.sprotaddr;
  155.             arp.sprotaddr = ip_addr;
  156.             arp.opcode = ARP_REPLY;
  157.             if((bp = htonarp(&arp)) == NULLBUF)
  158.                 return;
  159.  
  160.             if(interface->forw != NULLIF)
  161.                 (*interface->forw->output)(interface->forw,
  162.                  arp.thwaddr,interface->forw->hwaddr,at->arptype,bp);
  163.             else 
  164.                 (*interface->output)(interface,arp.thwaddr,
  165.                  interface->hwaddr,at->arptype,bp);
  166.             arp_stat.inreq++;
  167.         } else {
  168.             arp_stat.replies++;
  169.         }
  170.     } else if(arp.opcode == ARP_REQUEST
  171. #ifdef PROXY
  172.         && (ap = arp_lookup(arp.hardware,arp.tprotaddr)) != NULLARP
  173.                  && ap->pub){  /* The guy is published */
  174. #else
  175.         && (ap = arp_lookup(arp.hardware,arp.tprotaddr)) != NULLARP
  176.         && ap->pub){
  177.         /* Otherwise, respond if the guy he's looking for is
  178.          * published in our table.
  179.          */
  180. #endif
  181.         memcpy(arp.thwaddr,arp.shwaddr,(int16)uchar(arp.hwalen));
  182.         /* Mark the end of the sender's AX.25 address
  183.          * in case he didn't
  184.          */
  185.         if(arp.hardware == ARP_AX25)
  186.             arp.thwaddr[uchar(arp.hwalen)-1] |= E;
  187.         memcpy(arp.shwaddr,ap->hw_addr,at->hwalen);
  188.         arp.tprotaddr = arp.sprotaddr;
  189.         arp.sprotaddr = ap->ip_addr;
  190.         arp.opcode = ARP_REPLY;
  191.         if((bp = htonarp(&arp)) == NULLBUF)
  192.             return;
  193.         if(interface->forw != NULLIF)
  194.             (*interface->forw->output)(interface->forw,
  195.              arp.thwaddr,interface->forw->hwaddr,at->arptype,bp);
  196.         else 
  197.             (*interface->output)(interface,arp.thwaddr,
  198.              interface->hwaddr,at->arptype,bp);
  199.         arp_stat.inreq++;
  200. #ifdef PROXY
  201.     } else if(routing_inuse.is_es &&
  202.            (prox = is_es_lookup(arp.tprotaddr, arp.sprotaddr)) != NULLIS_ES
  203.              && prox->hardware == arp.hardware){
  204.         /* Is-es arp */
  205.         memcpy(arp.thwaddr,arp.shwaddr,(int16)uchar(arp.hwalen));
  206.         /* Mark the end of the sender's AX.25 address
  207.          * in case he didn't
  208.          */
  209.         if(arp.hardware == ARP_AX25)
  210.             arp.thwaddr[uchar(arp.hwalen)-1] |= E;
  211.         memcpy(arp.shwaddr,interface->hwaddr,at->hwalen);
  212.         temp = arp.tprotaddr;
  213.         arp.tprotaddr = arp.sprotaddr;
  214.         arp.sprotaddr = temp;
  215.         arp.opcode = ARP_REPLY;
  216.         if((bp = htonarp(&arp)) == NULLBUF)
  217.             return;
  218.         if(interface->forw != NULLIF)
  219.             (*interface->forw->output)(interface->forw,
  220.              arp.thwaddr,interface->forw->hwaddr,at->arptype,bp);
  221.         else 
  222.             (*interface->output)(interface,arp.thwaddr,
  223.              interface->hwaddr,at->arptype,bp);
  224.         arp_stat.inreq++;
  225.  
  226.         if(prox != NULLIS_ES)
  227.             is_es_stat.sent++;
  228.     }
  229. #else
  230.     }
  231. #endif
  232. }
  233. /* Add an IP-addr / hardware-addr pair to the ARP table */
  234. struct arp_tab *
  235. arp_add(ipaddr,hardware,hw_addr,hw_alen,pub)
  236. int32 ipaddr;        /* IP address, host order */
  237. int16 hardware;        /* Hardware type */
  238. char *hw_addr;        /* Hardware address, if known; NULLCHAR otherwise */
  239. int16 hw_alen;        /* Length of hardware address */
  240. int pub;        /* Publish this entry? */
  241. {
  242.     void arp_drop();
  243.     int ip_route();
  244.     struct mbuf *bp,*dequeue();
  245.     register struct arp_tab *ap;
  246.     unsigned hashval,arp_hash();
  247.  
  248.     if((ap = arp_lookup(hardware,ipaddr)) == NULLARP){
  249.         /* New entry */
  250.         if((ap = (struct arp_tab *)calloc(1,sizeof(struct arp_tab))) == NULLARP)
  251.             return NULLARP;
  252.         ap->timer.func = arp_drop;
  253.         ap->timer.arg = (char *)ap;
  254.         ap->hardware = hardware;
  255.         ap->ip_addr = ipaddr;
  256.  
  257.         /* Put on head of hash chain */
  258.         hashval = arp_hash(hardware,ipaddr);
  259.         ap->prev = NULLARP;
  260.         ap->next = arp_tab[hashval];
  261.         arp_tab[hashval] = ap;
  262.         if(ap->next != NULLARP){
  263.             ap->next->prev = ap;
  264.         }
  265.     }
  266.     if(hw_addr == NULLCHAR){
  267.         /* Await response */
  268.         ap->state = ARP_PENDING;
  269.         ap->timer.start = PENDTIME * (1000 / MSPTICK);
  270.     } else {
  271.         /* Response has come in, update entry and run through queue */
  272.         ap->state = ARP_VALID;
  273.         ap->timer.start = ARPLIFE * (1000 / MSPTICK);
  274.         if(ap->hw_addr != NULLCHAR)
  275.             free(ap->hw_addr);
  276.         if((ap->hw_addr = malloc(hw_alen)) == NULLCHAR){
  277.             free((char *)ap);
  278.             return NULLARP;
  279.         }
  280.         memcpy(ap->hw_addr,hw_addr,hw_alen);
  281.         /* This kludge marks the end of an AX.25 address to allow
  282.          * for optional digipeaters (insert Joan Rivers salute here)
  283.          */
  284.         if(hardware == ARP_AX25)
  285.             ap->hw_addr[hw_alen-1] |= E;
  286.         ap->pub = pub;
  287.         while((bp = dequeue(&ap->pending)) != NULLBUF)
  288.             ip_route(bp,0);
  289.     }
  290.     start_timer(&ap->timer);
  291.     return ap;
  292. }
  293.  
  294. /* Remove an entry from the ARP table */
  295. void
  296. arp_drop(ap)
  297. register struct arp_tab *ap;
  298. {
  299.     unsigned arp_hash();
  300.  
  301.     if(ap == NULLARP)
  302.         return;
  303.     stop_timer(&ap->timer);    /* Shouldn't be necessary */
  304.     if(ap->next != NULLARP)
  305.         ap->next->prev = ap->prev;
  306.     if(ap->prev != NULLARP)
  307.         ap->prev->next = ap->next;
  308.     else
  309.         arp_tab[arp_hash(ap->hardware,ap->ip_addr)] = ap->next;
  310.     if(ap->hw_addr != NULLCHAR)
  311.         free(ap->hw_addr);
  312.     free_q(&ap->pending);
  313.     free((char *)ap);
  314. }
  315.  
  316. /* Look up the given IP address in the ARP table */
  317. struct arp_tab *
  318. arp_lookup(hardware,ipaddr)
  319. int16 hardware;
  320. int32 ipaddr;
  321. {
  322.     unsigned arp_hash();
  323.     register struct arp_tab *ap;
  324.  
  325.     for(ap = arp_tab[arp_hash(hardware,ipaddr)]; ap != NULLARP; ap = ap->next){
  326.         if(ap->ip_addr == ipaddr && ap->hardware == hardware)
  327.             break;
  328.     }
  329.     return ap;
  330. }
  331. /* Send an ARP request to resolve IP address target_ip */
  332. static
  333. void
  334. arp_output(interface,hardware,target)
  335. struct interface *interface;
  336. int16 hardware;
  337. int32 target;
  338. {
  339.     struct arp arp;
  340.     struct mbuf *bp,*htonarp();
  341.     struct arp_type *at;
  342.  
  343.     at = &arp_type[hardware];
  344.     if(interface->output == NULLFP)
  345.         return;
  346.     
  347.     arp.hardware = hardware;
  348.     arp.protocol = at->iptype;
  349.     arp.hwalen = at->hwalen;
  350.     arp.pralen = sizeof(int32);
  351.     arp.opcode = ARP_REQUEST;
  352.     memcpy(arp.shwaddr,interface->hwaddr,at->hwalen);
  353.     arp.sprotaddr = ip_addr;
  354.     memset(arp.thwaddr,0,at->hwalen);
  355.     arp.tprotaddr = target;
  356.     if((bp = htonarp(&arp)) == NULLBUF)
  357.         return;
  358.     (*interface->output)(interface,at->bdcst,
  359.         interface->hwaddr,at->arptype,bp);
  360.     arp_stat.outreq++;
  361. }
  362.  
  363. /* Hash a {hardware type, IP address} pair */
  364. static
  365. unsigned
  366. arp_hash(hardware,ipaddr)
  367. int16 hardware;
  368. int32 ipaddr;
  369. {
  370.     register unsigned hashval;
  371.  
  372.     hashval = hardware;
  373.     hashval ^= hiword(ipaddr);
  374.     hashval ^= loword(ipaddr);
  375.     hashval %= ARPSIZE;
  376.     return hashval;
  377. }        
  378. /* Copy a host format arp structure into mbuf for transmission */
  379. struct mbuf *
  380. htonarp(arp)
  381. register struct arp *arp;
  382. {
  383.     struct mbuf *bp;
  384.     register char *buf;
  385.  
  386.     if(arp == (struct arp *)NULL)
  387.         return NULLBUF;
  388.     if((bp = alloc_mbuf(sizeof(struct arp))) == NULLBUF)
  389.         return NULLBUF;
  390.  
  391.     buf = bp->data;
  392.  
  393.     buf = put16(buf,arp->hardware);
  394.     buf = put16(buf,arp->protocol);
  395.     *buf++ = arp->hwalen;
  396.     *buf++ = arp->pralen;
  397.     buf = put16(buf,arp->opcode);
  398.     memcpy(buf,arp->shwaddr,(int16)uchar(arp->hwalen));
  399.     buf += arp->hwalen;
  400.     buf = put32(buf,arp->sprotaddr);
  401.     memcpy(buf,arp->thwaddr,(int16)uchar(arp->hwalen));
  402.     buf += arp->hwalen;
  403.     buf = put32(buf,arp->tprotaddr);
  404.  
  405.     bp->cnt = buf - bp->data;
  406.     return bp;
  407. }
  408. /* Convert an incoming ARP packet into a host-format structure */
  409. int
  410. ntoharp(arp,bpp)
  411. register struct arp *arp;
  412. struct mbuf **bpp;
  413. {
  414.     if(arp == (struct arp *)NULL || bpp == NULLBUFP)
  415.         return -1;
  416.  
  417.     arp->hardware = pull16(bpp);
  418.     arp->protocol = pull16(bpp);
  419.     arp->hwalen = pullchar(bpp);
  420.     arp->pralen = pullchar(bpp);
  421.     arp->opcode = pull16(bpp);
  422.     pullup(bpp,arp->shwaddr,(int16)uchar(arp->hwalen));
  423.     arp->sprotaddr = pull32(bpp);
  424.     pullup(bpp,arp->thwaddr,(int16)uchar(arp->hwalen));
  425.  
  426.     arp->tprotaddr = pull32(bpp);
  427.  
  428.     /* Get rid of anything left over */
  429.     free_p(*bpp);
  430.     *bpp = NULLBUF;
  431.     return 0;
  432. }
  433.  
  434.